#include "QxDataManagerPage.hpp"
#include "ui_QxDataManagerPage.h"

#include "QxTableModel.hpp"
#include "QxDatabasePool.hpp"

#include "QxWorkspaceIO.hpp"
#include "QxWellLasFile.hpp"
#include "QxWellDatabaseIO.hpp"
#include "QxWellInfoDataModel.hpp"

#include <QDir>
#include <QSqlError>
#include <QSqlQuery>
#include <QFileDialog>
#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlTableModel>
#include <QStringListModel>
#include <QStandardItemModel>
#include <QItemSelectionModel>

class QxDataManagerPage::QxDataManagerPagePrivate
{
public:

  QxDataManagerPagePrivate( QxDataManagerPage* me ) : m_self( me ) {
    m_ui.setupUi( m_self );
    m_ui.tvDatabase->setModel( &m_tableModel );

    QObject::connect( &theDatabasePool, SIGNAL( databaseChanged( const QSqlDatabase& ) ),
                      m_self,           SLOT( slotDatabaseChanged( const QSqlDatabase& ) ) );
    m_majorQuery = "select well_name from DB_WELLINFO";
  }

  bool openDatabase( const QString& filename ) {
    bool result  = false;
    if( !filename.isEmpty() ) {
      QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE" );
      db.setDatabaseName( filename );
      if( !db.open() || !(result=true) ) {
        QMessageBox::critical( m_self,
                               QObject::tr( "Cannot open database" ),
                               QObject::tr( "Unable to establish a database connection.\n"
                                            "This example needs SQLite support. Please read "
                                            "the Qt SQL driver documentation for information how "
                                            "to build it.\n\n"
                                            "Click Cancel to exit." ),
                               QMessageBox::Cancel );
      }
      theDatabasePool.setDatabase( db );
    }

    return result;
  }

  void init() {
    m_ui.tvWells->setModel( &m_wellNamesModel );
    m_ui.tvLogs->setModel( &m_wellLogNamesModel );

    QObject::connect( m_ui.tvWells->selectionModel(), SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
                      m_self, SLOT( slotWellSelectionChanged( const QItemSelection&, const QItemSelection& ) ) );
    QObject::connect( m_ui.tvLogs->selectionModel(), SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
                      m_self, SLOT( slotWellLogSelectionChanged( const QItemSelection&, const QItemSelection& ) ) );
  }

  void updateContentTable( const QVector<float>& data=QVector<float>() ) {
    m_tableModel.setBuffer( data );
  }

  void clearModel() {
    m_tableModel.setBuffer( QVector<float>() );
    m_wellNamesModel.setStringList( QStringList() );
    m_wellLogNamesModel.setStringList( QStringList() );
  }

  void processDatabaseChanged( const QSqlDatabase& db ) {
    clearModel();
    m_workspaceIO.setDatabase( db );
    m_wellNamesModel.setStringList( m_workspaceIO.queryWellNames() );
  }

  QString selectedWellName() const {
    return m_wellNamesModel.stringList().at( m_ui.tvWells->selectionModel()->currentIndex().row() );
  }

  QString selectedWellLogName() const {
    return m_wellLogNamesModel.stringList().at( m_ui.tvLogs->selectionModel()->currentIndex().row() );
  }

  QxDataManagerPage*         m_self;
  Ui::QxDataManagerPage      m_ui;

  QxTableModel               m_tableModel;
  QStringListModel           m_wellNamesModel;
  QStringListModel           m_wellLogNamesModel;

  QString                    m_majorQuery;

  QxWorkspaceIO              m_workspaceIO;
};

QxDataManagerPage::QxDataManagerPage( QWidget* parent )
  : QWidget( parent ), _pd( new QxDataManagerPagePrivate( this ) )
{
  _pd->init();
}

QxDataManagerPage::~QxDataManagerPage()
{
}

void QxDataManagerPage::on_newBtn_clicked()
{
  bool bFlag = false;

  QString filename =
    QFileDialog::getSaveFileName( this, tr( "Create New Database" ), QDir::currentPath(), tr( "All files (*.*)" ) );
  if( bFlag = _pd->openDatabase( filename ) ) {
    _pd->m_ui.txtFilename->setText( filename );
  }
}

void QxDataManagerPage::on_openBtn_clicked()
{
  QString filename =
    QFileDialog::getOpenFileName( this, tr( "Open Database" ), QDir::currentPath(), tr( "All files (*.*)" ) );
  if( _pd->openDatabase( filename ) ) {
    _pd->m_ui.txtFilename->setText( filename );
  }
}

void QxDataManagerPage::on_closeBtn_clicked()
{
  theDatabasePool.setDatabase( QSqlDatabase() );
  _pd->m_ui.txtFilename->clear();
}

void QxDataManagerPage::on_importBtn_clicked()
{
  QString title = tr( "Select Well Data File" );
  QString filter = tr( "Well data files (*.las)" );
  QStringList filenames = QFileDialog::getOpenFileNames( this, title, QDir::currentPath(), filter );
  Q_FOREACH( const QString& filename, filenames ) {
    if( !filename.isEmpty() ) {
      QxWellLasFile hLasFile;
      hLasFile.setFilename( filename );

      _pd->m_workspaceIO.insertWellInfoDefine( hLasFile.wellInfoDefine() );
      QxWellDatabaseIO wellDatabaseIO( theDatabasePool.database() );
      wellDatabaseIO.setWellName( hLasFile.wellInfoDefine().wellName );
      if( !hLasFile.prepare() ) {
        continue;
      }
      Q_FOREACH( const QxWellLogDefine& wellLogDefine, hLasFile.wellLogDefines() ) {
        wellDatabaseIO.insertWellLogDefine( wellLogDefine );
        wellDatabaseIO.setData( wellLogDefine.wellLogName, hLasFile.data( wellLogDefine.wellLogName ) );
      }
    }
  }
  _pd->processDatabaseChanged( theDatabasePool.database() );
}

void QxDataManagerPage::slotDatabaseChanged( const QSqlDatabase& db )
{
  bool bFlag = db.isOpen();
  _pd->m_ui.newBtn->setEnabled( !bFlag );
  _pd->m_ui.openBtn->setEnabled( !bFlag );
  _pd->m_ui.closeBtn->setEnabled( bFlag );
  _pd->m_ui.importBtn->setEnabled( bFlag );

  _pd->processDatabaseChanged( db );
}

void QxDataManagerPage::slotWellSelectionChanged( const QItemSelection&, const QItemSelection& )
{
  QxWellDatabaseIO wellDatabaseIO( theDatabasePool.database() );
  wellDatabaseIO.setWellName( _pd->selectedWellName() );
  _pd->m_wellLogNamesModel.setStringList( wellDatabaseIO.queryWellLogNames() );
}

void QxDataManagerPage::slotWellLogSelectionChanged( const QItemSelection& selected, const QItemSelection& )
{
  QxWellDatabaseIO wellDatabaseIO( theDatabasePool.database() );
  wellDatabaseIO.setWellName( _pd->selectedWellName() );

  QString wellLogName = _pd->m_wellLogNamesModel.stringList().at( selected.indexes().first().row() );
  _pd->updateContentTable( wellDatabaseIO.data( wellLogName ) );
}
